
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.io.IOException;

/**
 * Class GwRTC ...
 *
 * @author Ricardo Lima
 * @version 1.0, 14/Out/2008 12:12:41
 */
public class LogServer {

    private static final int DEFAULT_PORT = 30123;
    private static final String DEFAULT_CFG = "log_server.cfg";

    //server control fields
    private int thread_count = 0;
    private int max_threads = 100;
    private boolean running = true;
    private boolean stopped = false;
    private int port = DEFAULT_PORT;
    
    private String dbhost;
    private int dbport = Integer.MIN_VALUE;

    private LogWritter log;

    /**
     * Constructor LogServer creates a new LogServer instance.
     */
    public LogServer(String cfgPath) throws Exception {
        this.readLogConfig(cfgPath);
    }

    private void readLogConfig(String cfgPath) throws FileNotFoundException, IOException, Exception {
        BufferedReader reader = new BufferedReader(new FileReader(cfgPath));
        String line = null;

        String accessLogPath = null;
        String ordersLogPath = null;
        String shipmentLogPath = null;

        while((line = reader.readLine()) != null) {

            //line is a comment: ignore
            if (line.startsWith("#")) {
                continue;
            }

            String [] tokens = line.split("=");
            String key = tokens[0].trim();
            String val = tokens[1].trim();

            if (key.equalsIgnoreCase("access_log")) {
                accessLogPath = val;
            } else if (key.equalsIgnoreCase("orders_log")) {
                ordersLogPath = val;
            } else if (key.equalsIgnoreCase("shipment_log")) {
                shipmentLogPath = val;
            } else if (key.equalsIgnoreCase("port")) {
                this.port = Integer.parseInt(val);
            } else if (key.equalsIgnoreCase("dbhost")){
            	this.dbhost = val;
            } else if (key.equalsIgnoreCase("dbport")){
            	this.dbport = Integer.parseInt(val);
            }
        }

        if (accessLogPath == null ||
            ordersLogPath == null ||
            shipmentLogPath == null ||
            this.dbhost == null ||
            this.dbport == Integer.MIN_VALUE) {
            throw new Exception("missing configuration file");
        }
        this.log = new LogWritter(accessLogPath, ordersLogPath, shipmentLogPath);
    }

    /**
     * Method start ...
     */
    public void start() {

        try {

            // create the server socket
            ServerSocket serversocket = new ServerSocket(this.port);
            //5 seconds of timeout
            serversocket.setSoTimeout(5000);
            while(this.running) {
                // read from the socket
                try {

                    Socket socket = serversocket.accept();
                    int threadCounter = this.add_thread();
                    if((threadCounter != -1)){
                        socket.setSoTimeout(5000);
                        ConnectionHandler handler = new ConnectionHandler(socket, this, log);
                        handler.start();
                    }
                    else{
                        //reject request;
                        socket.close();
                    }

                } catch(SocketTimeoutException e) {
                    //evc.printStackTrace(e);
                } catch (SocketException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            System.out.println("ERROR initializing server socket");
            e.printStackTrace();
            System.exit(1);
        }

        synchronized (this) {
            while (this.thread_count > 0) {
                try {
                    System.out.println("Waiting for all threads to stop");
                    this.wait(2000);
                } catch (InterruptedException e) {
                }
            }
            this.stopped = true;
            System.out.println("stopped = true");
            this.notifyAll();
        }

        this.log.close();
    }

    /**
     * stop the server
     */
    public synchronized void stop() {
        this.running = false;
        while (!this.stopped) {
            try {
                System.out.println("Waiting for module to stop");
                this.wait(2000);
            } catch (InterruptedException e) {
            }
        }
    }

    /**
     * Add a new thread to the server
     * @return int number of occupied threads, -1 if full
     */
    public synchronized int add_thread() {
        // not accepting new connections
        if (!this.running) {
            return -1;
        }
        // thread queue is full
        if (this.thread_count >= this.max_threads) {
            System.out.println("thread queue is full, rejecting connections");
            return -1;
        }

        this.thread_count++;
        System.out.println("Threads++ (thread_number="+this.thread_count+")");
        return this.thread_count;
    }

    /**
     * Method free_thread ...
     */
    public synchronized void free_thread() {
        this.thread_count--;
        System.out.println("Threads-- (thread_number="+this.thread_count+")");
        this.notifyAll();
    }


    /**
     * Method isRunning returns the running of this GwRTC object.
     *
     * @return the running (type boolean) of this GwRTC object.
     */
    public boolean isRunning() {
        return running;
    }
    
    

    public String getDbhost() {
		return dbhost;
	}

	public void setDbhost(String dbhost) {
		this.dbhost = dbhost;
	}

	public int getDbport() {
		return dbport;
	}

	public void setDbport(int dbport) {
		this.dbport = dbport;
	}

	/**
     * Method main ...
     *
     * @param args of type String[]
     */
    public static void main(String [] args) {
        try {
            String cfg = DEFAULT_CFG;
            if (args.length>0) {
                cfg = args[0];
            }
            LogServer server = new LogServer(cfg);
            server.start();
        } catch(FileNotFoundException e) {
            System.out.println("--------------------------------------------------------");
            System.out.println("File not found: "+e.getMessage());
            System.out.println("--------------------------------------------------------");
            System.out.println("By default the system loads the file log_server.cfg");
            System.out.println("You may provide your own config file as argument");
            System.out.println("USAGE: ");
            System.out.println("LogServer cfg_file");
            System.out.println("--------------------------------------------------------");
            System.out.println("CONFIG FILE FORMAT:");
            System.out.println("# a comment");
            System.out.println("access_log=access log file path (mandatory)");
            System.out.println("orders_log=orders log file path (mandatory)");
            System.out.println("shipment_log=shipment log file path (mandatory)");
            System.out.println("port=server listen port (30123 if absent)");
            System.out.println("--------------------------------------------------------");
            System.exit(1);
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

}